#include "slog2/slog2.h"
#include "slog2/slog2_context.h"
#include "slog2/slog2_context_data.h"
#include "gtest/gtest.h"

#include <csignal>
#include <csetjmp>
#include <iostream>

using namespace ::testing;
//using namespace netaos::nosal::log;

#if 0
TEST(Slog2Test, Slog2RegisterApplication)
{
    std::string application_id = "slog2_reg_app";
    std::string description = "This is test for slog2";
    Slog2VerbosityLevel verbosity = Slog2VerbosityLevel::kDebug2;

    Slog2ReturnValue ret = Slog2RegisterApplication(application_id, description, verbosity);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
}

TEST(Slog2Test, Slog2UnregisterApplication)
{
    Slog2ReturnValue ret = Slog2UnregisterApplication();
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
}

TEST(Slog2ContextTest, Slog2ContextInitialize)
{
    std::string context_id = "slog2_test_context";
    std::string description = "This is test for slog2";
    Slog2VerbosityLevel verbosity = Slog2VerbosityLevel::kDebug2;
    Slog2Context slog2_context;
    Slog2ReturnValue ret = slog2_context.Initialize(context_id, description, verbosity);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
}
#endif
struct Slog2ApplicationTest : Test
{
    void SetUp() override
    {
        Slog2RegisterApplication(application_id, description, verbosity);
        slog2_context.Initialize("CTX", description, verbosity);
	slog2_context.EnableConsole(false);
	slog2_context.EnableRemote(false);
        data = new Slog2ContextData();
        data->Initialize(&slog2_context);
    }

    void TearDown() override
    {
        delete data;
        Slog2UnregisterApplication();
    }

    std::string application_id = "slog2_test_app";
    std::string description = "This is test for slog2";
    Slog2VerbosityLevel verbosity = Slog2VerbosityLevel::kDebug2;
    Slog2Context slog2_context;
    Slog2ContextData *data;
};

TEST_F(Slog2ApplicationTest, Slog2ContextDataWriteToConsole)
{
    slog2_context.EnableConsole(true);
    slog2_context.EnableRemote(false);

    Slog2ReturnValue ret = data->WriteStart(Slog2VerbosityLevel::kInfo);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    Slog2ReturnValue ret2 = data->Write("write to console");
    EXPECT_EQ(ret2, Slog2ReturnValue::kReturnOk);

    Slog2ReturnValue ret3 = data->WriteFinish();
    EXPECT_EQ(ret3, Slog2ReturnValue::kReturnOk);
}

TEST_F(Slog2ApplicationTest, Slog2ContextDataWriteToRemote)
{
    slog2_context.EnableRemote(true);
    slog2_context.EnableConsole(false);

    Slog2ReturnValue ret = data->WriteStart(Slog2VerbosityLevel::kInfo);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    Slog2ReturnValue ret2 = data->Write("write to remote");
    EXPECT_EQ(ret2, Slog2ReturnValue::kReturnOk);

    Slog2ReturnValue ret3 = data->WriteFinish();
    EXPECT_EQ(ret3, Slog2ReturnValue::kReturnOk);
}

TEST_F(Slog2ApplicationTest, Slog2ContextDataWriteToConsolAndRemote)
{
    slog2_context.EnableRemote(true);
    slog2_context.EnableConsole(true);

    Slog2ReturnValue ret = data->WriteStart(Slog2VerbosityLevel::kInfo);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    Slog2ReturnValue ret2 = data->Write("write to console and remote");
    EXPECT_EQ(ret2, Slog2ReturnValue::kReturnOk);

    Slog2ReturnValue ret3 = data->WriteFinish();
    EXPECT_EQ(ret3, Slog2ReturnValue::kReturnOk);
}


#if 0
TEST_F(Slog2ApplicationTest, Slog2ContextDataWriteToRemote)
{
   // slog2_context.EnableRemote(true);
    slog2_context.EnableConsole(false);

    Slog2ReturnValue ret0 = data->Initialize(&slog2_context);
    EXPECT_EQ(ret0, Slog2ReturnValue::kReturnOk);

    Slog2ReturnValue ret = data->WriteStart(Slog2VerbosityLevel::kInfo);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    Slog2ReturnValue ret2 = data->Write("abcdef");
    EXPECT_EQ(ret2, Slog2ReturnValue::kReturnOk);

    ret2 = data->Write(123456);
    EXPECT_EQ(ret2, Slog2ReturnValue::kReturnOk);

    ret2 = data->Write(true);
    EXPECT_EQ(ret2, Slog2ReturnValue::kReturnOk);

    ret2 = data->Write(3.1415926);
    EXPECT_EQ(ret2, Slog2ReturnValue::kReturnOk);

    Slog2ReturnValue ret3 = data->WriteFinish();
    EXPECT_EQ(ret3, Slog2ReturnValue::kReturnOk);
}

#endif

struct Slog2ContextDataTest : Test
{
    void SetUp() override
    {
        data = new Slog2ContextData();
    }

    void TearDown() override
    {
        delete data;
    }

    Slog2ContextData *data;
};

TEST_F(Slog2ContextDataTest, Slog2ContextData_WriteUint8)
{
    Slog2ReturnValue ret = data->WriteStart(Slog2VerbosityLevel::kInfo);

    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    uint8_t min_value = 0;
    ret = data->Write(min_value);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    std::string read_string;
    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("0"));

    data->WriteStart();
    uint8_t max_value = 255;
    ret = data->Write(max_value);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("255"));
}


TEST_F(Slog2ContextDataTest, Slog2ContextData_WriteUint16)
{
    Slog2ReturnValue ret = data->WriteStart(
                    Slog2VerbosityLevel::kInfo);

    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    uint16_t min_value = 0;
    ret = data->Write(min_value);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    std::string read_string;
    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("0"));

    data->WriteStart();
    uint16_t max_value = 65535;
    ret = data->Write(max_value);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("65535"));
}

TEST_F(Slog2ContextDataTest, Slog2ContextData_WriteUint32)
{
    Slog2ReturnValue ret = data->WriteStart(
                    Slog2VerbosityLevel::kInfo);

    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    uint32_t min_value = 0;
    ret = data->Write(min_value);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    std::string read_string;
    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("0"));


    data->WriteStart();
    uint32_t max_value = 4294967295;
    ret = data->Write(max_value);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("4294967295"));
}

TEST_F(Slog2ContextDataTest, Slog2ContextData_WriteUint64)
{
    Slog2ReturnValue ret = data->WriteStart(
                    Slog2VerbosityLevel::kInfo);

    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    uint64_t min_value = 0;
    ret = data->Write(min_value);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    std::string read_string;
    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("0"));

    data->WriteStart();
    uint64_t max_value = 18446744073709551615ull;
    ret = data->Write(max_value);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("18446744073709551615"));
}

TEST_F(Slog2ContextDataTest, Slog2ContextData_WriteInt8)
{
    Slog2ReturnValue ret = data->WriteStart(
                    Slog2VerbosityLevel::kInfo);

    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    int8_t min_value = -128;
    ret = data->Write(min_value);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    std::string read_string;
    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("-128"));

    data->WriteStart();
    int8_t max_value = 127;
    ret = data->Write(max_value);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("127"));
}


TEST_F(Slog2ContextDataTest, Slog2ContextData_WriteInt16)
{
    Slog2ReturnValue ret = data->WriteStart(
                    Slog2VerbosityLevel::kInfo);

    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    int16_t min_value = -32768;
    ret = data->Write(min_value);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    std::string read_string;
    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("-32768"));

    data->WriteStart();
    int16_t max_value = 32767;
    ret = data->Write(max_value);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("32767"));
}


TEST_F(Slog2ContextDataTest, Slog2ContextData_WriteInt32)
{
    Slog2ReturnValue ret = data->WriteStart(
                    Slog2VerbosityLevel::kInfo);

    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    int32_t min_value = -2147483648;
    ret = data->Write(min_value);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    std::string read_string;
    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("-2147483648"));

    data->WriteStart();
    int32_t max_value = 2147483647;
    ret = data->Write(max_value);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("2147483647"));
}


TEST_F(Slog2ContextDataTest, Slog2ContextData_WriteInt64)
{
    Slog2ReturnValue ret = data->WriteStart(
                    Slog2VerbosityLevel::kInfo);

    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    int64_t min_value = -9223372036854775808ll;
    ret = data->Write(min_value);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    std::string read_string;
    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("-9223372036854775808"));

    data->WriteStart();
    int64_t max_value = 9223372036854775807ll;
    ret = data->Write(max_value);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("9223372036854775807"));
}


TEST_F(Slog2ContextDataTest, Slog2ContextData_WriteFloat)
{
    Slog2ReturnValue ret = data->WriteStart(
                    Slog2VerbosityLevel::kInfo);

    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    float min_value = -12345678.123456; //-3.40E+38 ~ +3.40E+38
    ret = data->Write(min_value);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    std::string read_string;
    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("-12345678.000000"));

    data->WriteStart();
    float max_value = 12345678.1;
    ret = data->Write(max_value);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("12345678.000000"));
}

TEST_F(Slog2ContextDataTest, Slog2ContextData_WriteDouble)
{
    Slog2ReturnValue ret = data->WriteStart(
                    Slog2VerbosityLevel::kInfo);

    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    double min_value = -12345678.999999; //-1.79E+308 ~ +1.79E+308
    ret = data->Write(min_value);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    std::string read_string;
    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("-12345678.999999"));

    data->WriteStart();
    double max_value = 12345678.999999;
    ret = data->Write(max_value);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("12345678.999999"));
}


TEST_F(Slog2ContextDataTest, Slog2ContextData_WriteString)
{
    Slog2ReturnValue ret0 = data->Initialize(NULL);
    Slog2ReturnValue ret = data->WriteStart(
                    Slog2VerbosityLevel::kInfo);

    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    std::string value = "This is the test of string";
    ret = data->Write(value);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    std::string read_string;
    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("This is the test of string"));

    data->WriteStart();
    char char_value[] = "This is the test of char*!";
    ret = data->Write(char_value);
    //ret = data->Write(value.c_str());
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    read_string.clear();
    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("This is the test of char*!"));
}


TEST_F(Slog2ContextDataTest, Slog2ContextData_WriteVector)
{
    Slog2ReturnValue ret = data->WriteStart(
                    Slog2VerbosityLevel::kInfo);

    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    std::vector<uint8_t> value = {1,2,3,4,5};
    ret = data->Write(value);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);

    std::string read_string;
    ret = data->Read(read_string);
    EXPECT_EQ(ret, Slog2ReturnValue::kReturnOk);
    EXPECT_EQ(read_string, std::string("0102030405"));
}
